/* 
    本文件列举常见创建 observable 的方法
        create  of from fromEvent fromPromise never empty throw interval timer
*/

const observable = Rx.Observable.create(function (observer) {
    observer.next("Jerry");
    observer.next("Anna");
    observer.complete();
    observer.next("not work");
});

/* 
    观察者的三个方法(method)：

	next：每当Observable 发送出新的值，next 方法就会被呼叫。
	
	complete：在Observable 没有其他的资料可以取得时，complete 方法就会被呼叫，在complete 被呼叫之后，next 方法就不会再起作用。
	
	error：每当Observable 内发生错误时，error 方法就会被呼叫。 
*/
const observer = {
    next: function (value) {
        console.log(value);
    },
    error: function (error) {
        console.log(error);
    },
    complete: function () {
        console.log("complete");
    },
};

// 用我們定義好的觀察者，來訂閱這個 observable
observable.subscribe(observer);
// 上面的范例可以看得出来在complete 执行后，next 就会自动失效，所以没有印出not work。

/* 当我们想要同步的传递几个值时，就可以用 of 这个operator 来简洁的表达! */
const source = Rx.Observable.of('Jerry', 'Anna');

source.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log(error)
    }
});

// Jerry
// Anna
// complete!

/* 
    可能已经有人发现其实 of operator 的一个一个参数其实就是一个list，而list 在JavaScript 中最常见的形式是阵列(array)，那我们有没有办法把一个已存在的阵列当作参数呢？
    有的，我们可以用 from 来接收任何可列举的参数！
*/
const arr2 = ['Jerry', 'Anna', 2016, 2017, '30 days'] 
const source2 = Rx.Observable.from(arr2);

source.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log(error)
    }
});

// Jerry
// Anna
// 2016
// 2017
// 30 days
// complete!
/* 记得任何可列举的参数都可以用喔，也就是说像Set, WeakSet, Iterator 等都可以当作参数！ */

// 另外from 还能接收字串(string)，如下

const source3 = Rx.Observable.from('鐵人賽');

source3.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log(error)
    }
});
// 鐵
// 人
// 賽
// complete!

/*  
    我们也可以传入Promise 物件，如下
    如果我们传入Promise 物件实例，当正常回传时，就会被送到next，并立即送出完成通知，如果有错误则会送到error。
*/
const source4 = Rx.Observable
  .from(new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Hello RxJS!');
    },3000)
  }))
  
source4.subscribe({
    next: function(value) {
    	console.log(value)
    },
    complete: function() {
    	console.log('complete!');
    },
    error: function(error) {
    console.log(error)
    }
});

// Hello RxJS!
// complete!

/* 
    我们也可以用Event 建立Observable，透过 fromEvent 的方法，如下
*/
const source5 = Rx.Observable.fromEvent(document.body, 'click');

source5.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log(error)
    }
});

/* 
    fromEventPattern
    要用Event 来建立Observable 实例还有另一个方法fromEventPattern，这个方法是给类事件使用。所谓的类事件就是指其行为跟事件相像，
    同时具有注册监听及移除监听两种行为，就像DOM Event 有 addEventListener 及 removeEventListener 一样！
*/

class Producer {
	constructor() {
		this.listeners = [];
	}
	addListener(listener) {
		if(typeof listener === 'function') {
			this.listeners.push(listener)
		} else {
			throw new Error('listener 必須是 function')
		}
	}
	removeListener(listener) {
		this.listeners.splice(this.listeners.indexOf(listener), 1)
	}
	notify(message) {
		this.listeners.forEach(listener => {
			listener(message);
		})
	}
}
// ------- 以上都是之前的程式碼 -------- //

const egghead = new Producer(); 
// egghead 同時具有 註冊監聽者及移除監聽者 兩種方法

const source6 = Rx.Observable
    .fromEventPattern(
        (handler) => egghead.addListener(handler), 
        (handler) => egghead.removeListener(handler)
    );
  
source6.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log(error)
    }
})

egghead.notify('Hello! Can you hear me?');
// Hello! Can you hear me?

/* 
    empty, never, throw
    empty: 有点像是数学上的 零(0)，虽然有时候好像没什么，但却非常的重要。在Observable 的世界里也有类似的东西，像是empty
    never: 数学上还有一个跟零(0)很像的数，那就是 无穷(∞)，在Observable 的世界里我们用 never 来建立无穷的observable
    throw: 最后还有一个operator throw，它也就只做一件事就是抛出错误。

    这三个operators 虽然目前看起来没什么用，但之后在文章中大家就会慢慢发掘它们的用处！
*/
const source7 = Rx.Observable.empty();
// empty会给我们一个空的observable，如果我们订阅这个observable 会发生什么事呢？它会立即送出complete 的讯息！
source7.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log(error)
    }
});
// complete!

const source8 = Rx.Observable.never();

/* 
    never 会给我们一个无穷的observable，如果我们订阅它又会发生什么事呢？...什么事都不会发生，它就是一个一直存在但却什么都不做的observable。
    可以把never 想像成一个结束在无穷久以后的observable，但你永远等不到那一天！
    题外话，笔者一直很喜欢平行线的解释： 两条平行线就是它们相交于无穷远 
*/
source8.subscribe({
    next: function(value) {
        console.log(value)
    },
    complete: function() {
        console.log('complete!');
    },
    error: function(error) {
        console.log(error)
    }
});

// 下面这段程式码就只会log 出'Throw Error: Oop!'。
const source9 = Rx.Observable.throw('Oop!');

source9.subscribe({
	next: function(value) {
		console.log(value)
	},
	complete: function() {
		console.log('complete!');
	},
	error: function(error) {
    console.log('Throw Error: ' + error)
	}
});
// Throw Error: Oop!

/* 
    Subscription
    今天我们讲到很多无穷的observable，例如interval, never。但有时我们可能会在某些行为后不需要这些资源，
    要做到这件事最简单的方式就是unsubscribe。
    注意：  
        Events observable 尽量不要用unsubscribe，通常我们会使用takeUntil，在某个事件发生后来完成Event observable，这个部份我们之后会讲到！
*/

var source10 = Rx.Observable.timer(1000, 1000);

// 取得 subscription
var subscription = source10.subscribe({
	next: function(value) {
		console.log(value)
	},
	complete: function() {
		console.log('complete!');
	},
	error: function(error) {
    console.log('Throw Error: ' + error)
	}
});

setTimeout(() => {
    subscription.unsubscribe() // 停止訂閱(退訂)， RxJS 4.x 以前的版本用 dispose()
}, 5000);
// 0
// 1
// 2
// 3
// 4